--[[----------------------------------------------------------------------------
Adobe Photoshop Lightroom export plugin for Yandex.Fotki service
Version 1.0 RC2
http://aldeg.com/lightroom-plugins/
--------------------------------------------------------------------------------
$Id: YaFotkiAccount.lua 8 2009-04-26 18:41:22Z adegtiar $
--------------------------------------------------------------------------------
Copyright (c) 2009 Alexander A. Degtiar <adegtiar@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

--------------------------------------------------------------------------------
Based on completely reworked YaFotki 0.2.3 plugin by Alexander Artemenko
Many thanks for his work
http://svetlyak.ru/blog/lightroom-plugins/
------------------------------------------------------------------------------]]

local LrXml = import 'LrXml'
YaFotkiAccount = {}
local doingLogin = false
local doingLogout = false

local function storedCredentialsAreValid()
	return prefs.userLogin
end

function YaFotkiAccount.notLoggedIn( propertyTable )
	debug( 'Not logged in' )

	prefs.userLogin = nil
	propertyTable.accountStatus = "Not logged in"
	propertyTable.loginButtonTitle = "Log In"
	propertyTable.loginButtonEnabled = true
	propertyTable.validAccount = false
	propertyTable.albums = {}
end

function YaFotkiAccount.updateStatus( propertyTable )
	if storedCredentialsAreValid() then
		propertyTable.accountStatus = "Logged in as " .. prefs.userLogin
		propertyTable.loginButtonTitle = "Logout"
		propertyTable.loginButtonEnabled = true
		
		if propertyTable.selectedAlbum and propertyTable.selectedAlbum ~= 0 then
            propertyTable.LR_canExport = true
            propertyTable.LR_cantExportBecause = nil
		else
            propertyTable.LR_canExport = false
            propertyTable.LR_cantExportBecause = "Upload album not selected"
		end
		propertyTable.loginButtonAction = function()
			YaFotkiAccount.logout( propertyTable )
		end
	else
		propertyTable.LR_canExport = false
		propertyTable.LR_cantExportBecause = "You haven't logged in to Yandex.Fotki yet."
		YaFotkiAccount.notLoggedIn( propertyTable )
		propertyTable.loginButtonAction = function()
			YaFotkiAccount.signupDialog( propertyTable )
		end
	end

end

function YaFotkiAccount.verifyLogin( propertyTable )
	prefs:addObserver( 'userLogin', 
		function() 
			YaFotkiAccount.updateStatus ( propertyTable )
		end
	)
	YaFotkiAccount.updateStatus(propertyTable)
	YaFotkiAccount.loadAlbumsList( propertyTable )
end

function YaFotkiAccount.loadAlbumsList( propertyTable )
	if not storedCredentialsAreValid() then
		debug('Not logged in, skip retrieving albums list')
		return false
	end
	
	debug('Retrieving albums list')
	LrFunctionContext.postAsyncTaskWithContext( 'Yandex.Fotki albumslist',
	function( context )
        LrDialogs.showModalProgressDialog( { 
            title = 'Retrieving albums list...',
            cannotCancel = true,
            functionContext = context
        })
	
		local xml_path = LrFileUtils.chooseUniqueFileName( LrPathUtils.child(tmp_path, 'data.xml') )

		context:addCleanupHandler( function()
			LrFileUtils.delete( xml_path )
			YaFotkiAccount.updateStatus( propertyTable )
		end )
		
		context:addFailureHandler( function()
			LrDialogs.message("Can't retrieve albums list")
		end )
	
		propertyTable.accountStatus = "Loading albums..."
		propertyTable.loginButtonEnabled = false
	
		local client_xml = '<?xml version="1.0" encoding="utf-8"?><client-upload name="get-albums"/>'
		local xml = io.open(xml_path, 'wt')
		xml:write(client_xml)
		xml:close()

		local url = 'http://up.fotki.yandex.ru/upload'
		local result, headers = LrHttp.postMultipart(url,
			{
				{ name = 'query-type', value = 'photo-command' },
				{ name = 'command-xml', fileName = 'data.xml', filePath = xml_path, contentType = 'text/xml' },
			}
		)

		if isDebug then
			local f = io.open(LrPathUtils.child(tmp_path, 'albums.xml'), 'wt')
			f:write(result)
			f:close()
		end
		if not headers or (headers and headers.status ~= 200) then
			if headers.status == 403 then
				prefs.userLogin = nil
			else
				local status = ''
				if (headers) then
					status = tostring(headers.status)
				end
				local errString = 'Error retrieving albums list, HTTP response: ' .. status
				debug(errString)
				LrDialogs.message(errString)
			end
			return false
		end

		debug('Retrieving albums done. Now parsing...')

		local albums = {}
		local xml = LrXml.parseXml(result)

		local albumsCount = xml:childCount()
		for albumIndex = 1, albumsCount do
			local e = xml:childAtIndex(albumIndex)
			if e:name() == 'album' then
				attrib = e:attributes()
				local albumCaption = findXmlNode('title', e)
				if albumCaption then
					albums[#albums+1] = {title=albumCaption:text(), value=attrib.id.value}
				end
			end
		end
		albums[#albums+1] = {
			title='Create album...',
			value=0
		}
		propertyTable.albums = albums
		--LrDialogs.message(propertyTable.selectedAlbum)
		
        if propertyTable.selectedAlbum and propertyTable.selectedAlbum == 0 then
            propertyTable.selectedAlbum = nil
        end
		
		-- check if selected album exists in list
		local i
		local isAlbumValid = false 
		if propertyTable.selectedAlbum then
            for i = 1, #albums do
                if albums[i].value == propertyTable.selectedAlbum then
                    isAlbumValid = true
                    break
                end
            end
		end
		
		if not isAlbumValid then
		    propertyTable.selectedAlbum = nil
		end
		
		if not propertyTable.selectedAlbum and #albums > 1 then
			-- change to first available
			propertyTable.selectedAlbum = albums[1].value
		end

		debug('Albums parsing done.')
		return true
	end)
end


function YaFotkiAccount.logout( propertyTable )
	if doingLogout then
		debug('Logout in progress')
		return
	end
	doingLogout = true
	LrFunctionContext.postAsyncTaskWithContext( 'Yandex.Fotki logout',
	function( context )
		debug('Processing logout')
		context:addCleanupHandler( function()
			doingLogout = false
			propertyTable.loginButtonEnabled = true
		end )

		propertyTable.accountStatus = "Doing logout..."
		propertyTable.loginButtonEnabled = false

		local url = 'http://passport.yandex.ru/passport?mode=logout'
		local result, headers = LrHttp.get(url)
		if (headers or headers.status==200) then
			prefs.userLogin = nil
			debug('Logout done')
		else
			debug('Logout failed.')
			LrDialogs.message('Logout failed.')
		end
	end)
end

function YaFotkiAccount.login( propertyTable )
	if doingLogin then
		debug('Logging in progress')
		return
	end
	doingLogin = true

	debug('Logging in...')
	LrFunctionContext.postAsyncTaskWithContext( 'Yandex.Fotki login',
	function( context )
		YaFotkiAccount.notLoggedIn( propertyTable )

		context:addCleanupHandler( function()
			doingLogin = false
		end )
		
		context:addFailureHandler( function()
			doingLogin = false

			if not storedCredentialsAreValid() then
				YaFotkiAccount.notLoggedIn( propertyTable )
			end
		end )

		propertyTable.accountStatus = "Logging in..."
		propertyTable.loginButtonEnabled = false

		local url = 'https://passport.yandex.ru/passport?mode=auth&login=%s&passwd=%s&twoweeks=yes'
		url = string.format(url, escape(propertyTable.signupLogin), escape(propertyTable.signupPassword))
		local body, headers = LrHttp.get(url)
		if isDebug then
			local f = io.open(LrPathUtils.child(tmp_path, 'ya-auth.html'), 'wt')
			f:write(table2string(headers))
			f:write(body)
			f:close()
		end
		prefs.userLogin = propertyTable.signupLogin
		debug('Login done, trying to retrieve albums due we cannot check status')
		YaFotkiAccount.loadAlbumsList( propertyTable )
	end)
end

function YaFotkiAccount.albumChanged( propertyTable )
	if propertyTable.selectedAlbum == 0 then
		YaFotkiAccount.newAlbumDialog( propertyTable )
	end
	YaFotkiAccount.updateStatus(propertyTable)
end

function YaFotkiAccount.signupDialog( propertyTable )
	local bind = LrView.bind
    local f = LrView.osFactory()

    local contents = f:column {
        spacing = f:control_spacing(),
        bind_to_object = propertyTable,
        f:row {
            f:static_text { title = 'Login', width = LrView.share('sign_label') },
            f:edit_field {value = bind('signupLogin') },
        },
        f:row {
            f:static_text { title = 'Password', width = LrView.share('sign_label') },
            f:password_field {value = bind('signupPassword') },
        },
        f:row {
            f:static_text { title = 'Remember', width = LrView.share('sign_label') },
            f:checkbox {value = bind('signupRemember') },
        },
    }

	propertyTable.signupRemember = prefs.rememberMe or false

    local result
	repeat
		result = LrDialogs.presentModalDialog{
			title = 'Signup to fotki.yandex.ru',
			contents = contents,
		}
		propertyTable.signupLogin = trim(propertyTable.signupLogin or '')
		if result == 'ok' then
			if propertyTable.signupLogin ~= "" then 
				break
			else
				LrDialogs.message("Login can't be empty")
			end
		end
	until result == 'cancel'
	
    if result == 'ok' then
		prefs.rememberMe = propertyTable.signupRemember
		YaFotkiAccount.login( propertyTable )
    end
end

function YaFotkiAccount.createNewAlbum( propertyTable, title, description )
    debug('Creating new album with name ' .. title)
	
	LrFunctionContext.postAsyncTaskWithContext( 'Yandex.Fotki albumslist',
	function( context )
        LrDialogs.showModalProgressDialog( { 
            title = 'Creating album...',
            cannotCancel = true,
            functionContext = context
        })

		title = xmlSafe(title)
		description = xmlSafe(description)
		
		local url = 'http://up.fotki.yandex.ru/upload'
		local xml_path = LrFileUtils.chooseUniqueFileName( LrPathUtils.child(tmp_path, 'data.xml') )

		context:addCleanupHandler( function()
			LrFileUtils.delete( xml_path )
			YaFotkiAccount.loadAlbumsList( propertyTable )
		end )
		
		context:addFailureHandler( function()
			LrDialogs.message("Can't create album")
		end )

		local client_xml = '<?xml version="1.0" encoding="utf-8"?>' ..
			'<client-upload name="create-album">' ..
			'<album access="private">' ..
			'<title>' .. title .. '</title>' ..
			'<description>' .. description .. '</description>' ..
			'</album>' ..
			'</client-upload>'
		local xml = io.open(xml_path, 'wt')
		xml:write(client_xml)
		xml:close()
		local result, headers = LrHttp.postMultipart(url,
			{
				{ name = 'query-type', value = 'photo-command' },
				{ name = 'command-xml', fileName = 'data.xml', filePath = xml_path, contentType = 'text/xml' },
			}
		)

		if isDebug then
			local f = io.open(LrPathUtils.child(tmp_path, 'new-album.xml'), 'wt')
			f:write(result)
			f:close()
		end
		if not headers or (headers and headers.status ~= 200) then
			local status = ''
			if (headers) then
				status = tostring(headers.status)
			end
			local errString = 'Error creating album, HTTP response: ' .. status
			debug(errString)
			LrDialogs.message(errString)
			return false
		end
		--[[
		local f = io.open(LrPathUtils.child(tmp_path, 'new-album.xml'), 'r')
		local result = f:read("*all")
		f:close()
		]]--
		
		debug('Parsing response')
		local node = LrXml.parseXml(result)
		debug('Root node found')

		local newAlbumId = node:childAtIndex(1):attributes().id.value

		propertyTable.selectedAlbum = newAlbumId

		debug('Album created, id=' .. newAlbumId)
	end)
end

function YaFotkiAccount.newAlbumDialog( propertyTable )
    local f = LrView.osFactory()
    local bind = LrView.bind
    local p = propertyTable

    local contents = f:column {
        spacing = f:control_spacing(),
        bind_to_object = propertyTable,
        f:row {
            f:static_text {
				title = 'Album title',
				width = LrView.share('new_album_label') 
			},
            f:edit_field {
				width_in_chars = 40,
				value = bind('newAlbum_title') 
			},
        },
        f:row {
            f:static_text {
				title = 'Description', 
				width = LrView.share('new_album_label')
			},
            f:edit_field {
				value = bind('newAlbum_description'),
				height_in_lines=4,
				width_in_chars = 40,
			},
        },
		actionBinding = function()
			LrDialogs.message('OK')
		end
    }
	local result
	
	local lastSelectedAlbum = propertyTable.selectedAlbum
	
	repeat
		result = LrDialogs.presentModalDialog{
			title = 'Create new album',
			contents = contents,
		}
		propertyTable.newAlbum_title = trim(propertyTable.newAlbum_title or '')
		propertyTable.newAlbum_description = trim(propertyTable.newAlbum_description or '')
		if result == 'ok' then
			if propertyTable.newAlbum_title ~= "" then 
				break
			else
				LrDialogs.message("Album title can't be empty")
			end
		end
	until result == 'cancel'
	 
	
	propertyTable.selectedAlbum = lastSelectedAlbum
	
    if result == 'ok' then
   		YaFotkiAccount.createNewAlbum( propertyTable, propertyTable.newAlbum_title, propertyTable.newAlbum_description )
    end
end
